home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / util2 / pgp22src.zip / SRC / MPIIO.C < prev    next >
C/C++ Source or Header  |  1993-03-07  |  22KB  |  749 lines

  1. /*    mpiio.c - C source code for multiprecision integer I/O routines.
  2.     Implemented Nov 86 by Philip Zimmermann
  3.     Last revised 13 Sep 91 by PRZ
  4.  
  5.     Boulder Software Engineering
  6.     3021 Eleventh Street
  7.     Boulder, CO 80304
  8.     (303) 541-0140
  9.  
  10.     (c) Copyright 1986-92 by Philip Zimmermann.  All rights reserved.
  11.     The author assumes no liability for damages resulting from the use 
  12.     of this software, even if the damage results from defects in this 
  13.     software.  No warranty is expressed or implied.  
  14.  
  15.     These routines are for multiprecision arithmetic I/O functions for
  16.     number-theoretic cryptographic algorithms such as ElGamal,
  17.     Diffie-Hellman, Rabin, or factoring studies for large composite
  18.     numbers, as well as Rivest-Shamir-Adleman (RSA) public key
  19.     cryptography.
  20.  
  21.     The external data representation for RSA messages and keys that
  22.     some of these library routines assume is outlined in a paper by 
  23.     Philip Zimmermann, "A Proposed Standard Format for RSA Cryptosystems",
  24.     IEEE Computer, September 1986, Vol. 19 No. 9, pages 21-34.
  25.     Some revisions to this data format have occurred since the paper
  26.     was published.
  27. */
  28.  
  29. /* #define DEBUG */
  30.  
  31.  
  32. #ifndef EMBEDDED    /* not EMBEDDED - not compiling for embedded target */
  33. #include <stdio.h>     /* for printf, etc. */
  34. #else    /* EMBEDDED - compiling for embedded target */
  35. #define NULL (void *)0
  36. #endif
  37.  
  38. #include "mpilib.h"
  39. #include "mpiio.h"
  40. #include "pgp.h"
  41.  
  42. static void puthexbyte(byte b); /* Put out byte in ASCII hex via putchar. */
  43. static
  44. void puthexw16(word16 w); /* Put out 16-bit word in hex, high byte first. */
  45. static
  46. void putstr(string s); /* Put out null-terminated ASCII string via putchar. */
  47.  
  48. /*----------------- Following procedures relate to I/O ------------------*/
  49.  
  50. int string_length(char *s)
  51.     /* Returns string length, just like strlen() from <string.h> */
  52. {    int i;
  53.     i = 0;
  54.     if (s != NULL)
  55.         while (*s++) i++;
  56.     return (i);    
  57. }    /* string_length */
  58.  
  59.  
  60. #ifdef DEBUG
  61. static int ctox(int c)
  62.     /* Returns integer 0-15 if c is an ASCII hex digit, -1 otherwise. */
  63. {    if ((c >= '0') && (c <= '9'))
  64.         return(c - '0');
  65.     if ((c >= 'a') && (c <= 'f'))
  66.         return((c - 'a') + 10);
  67.     if ((c >= 'A') && (c <= 'F'))
  68.         return((c - 'A') + 10);
  69.     return(-1);        /* error -- not a hex digit */
  70. }    /* ctox */
  71.  
  72.  
  73. int str2reg(unitptr reg,string digitstr)
  74.     /* Converts a possibly-signed digit string into a large binary number.
  75.        Returns assumed radix, derived from suffix 'h','o',b','.' */
  76. {    unit temp[MAX_UNIT_PRECISION],base[MAX_UNIT_PRECISION];
  77.     int c,i;
  78.     boolean minus = FALSE;
  79.     short radix;    /* base 2-16 */
  80.  
  81.     mp_init(reg,0);
  82.     
  83.     i = string_length(digitstr);
  84.     if (i==0) return(10);        /* empty string, assume radix 10 */
  85.     c = digitstr[i-1];        /* get last char in string */
  86.     
  87.     switch (c)    /* classify radix select suffix character */
  88.     {
  89.     case '.':    radix = 10;
  90.             break;
  91.     case 'H':
  92.     case 'h':    radix = 16;
  93.             break;
  94.     case 'O': 
  95.     case 'o':    radix = 8;
  96.             break;
  97.     case 'B':
  98.     case 'b':    radix = 2;    /* caution! 'b' is a hex digit! */
  99.             break;
  100.     default:    radix = 10;
  101.     }
  102.  
  103.     mp_init(base,radix);
  104.     if ((minus = (*digitstr == '-')) != 0) digitstr++;
  105.     while ((c = *digitstr++) != 0)
  106.     {    if (c==',') continue;    /* allow commas in number */
  107.         c = ctox(c);
  108.         if ((c < 0) || (c >= radix)) 
  109.             break;    /* scan terminated by any non-digit */
  110.         mp_mult(temp,reg,base);
  111.         mp_move(reg,temp);
  112.         mp_init(temp,c);
  113.         mp_add(reg,temp);
  114.     }
  115.     if (minus) mp_neg(reg);
  116.     return(radix);
  117. } /* str2reg */
  118.  
  119. #endif    /* DEBUG */
  120.  
  121. /*    These I/O functions, such as putstr, puthexbyte, and puthexw16, 
  122.     are provided here to avoid the need to link in printf from the 
  123.     C I/O library.  This is handy in an embedded application.
  124.     For embedded applications, use a customized putchar function, 
  125.     separately compiled.
  126. */
  127.  
  128. static void putstr(string s)
  129.     /* Put out null-terminated ASCII string via putchar. */
  130. {    while (*s) putchar(*s++);
  131. }    /* putstr */
  132.  
  133. static void puthexbyte(byte b)
  134.     /* Put out byte in ASCII hex via putchar. */
  135. {    static char *nibs = "0123456789ABCDEF";
  136.     putchar(nibs[b >> 4]);
  137.     putchar(nibs[b & 0x0F]);
  138. }    /* puthexbyte */
  139.  
  140. static void puthexw16(word16 w)
  141.     /* Put out 16-bit word in hex, high byte first. */
  142. {    puthexbyte((byte)(w >> 8));
  143.     puthexbyte((byte)(w & 0xFF));
  144. }    /* puthexw16 */
  145.  
  146. #ifdef UNIT32
  147. static void puthexw32(word32 lw)
  148.     /* Puts out 32-bit word in hex, high byte first. */
  149. {    puthexw16((word16)(lw>>16));
  150.     puthexw16((word16)(lw & 0xFFFFL));
  151. }    /* puthexw32 */
  152. #endif    /* UNIT32 */
  153.  
  154.  
  155. #ifdef UNIT8
  156. #define puthexunit(u) puthexbyte(u)
  157. #endif
  158. #ifdef UNIT16
  159. #define puthexunit(u) puthexw16(u)
  160. #endif
  161. #ifdef UNIT32
  162. #define puthexunit(u) puthexw32(u)
  163. #endif
  164.  
  165. #ifdef DEBUG
  166. int display_in_base(string s,unitptr n,short radix)
  167.     /* Display n in any base, such as base 10.  Returns number of digits. */
  168.     /*    s is string to label the displayed register.
  169.         n is multiprecision integer.
  170.         radix is base, 2-16. 
  171.     */
  172. {
  173.     char buf[MAX_BIT_PRECISION + (MAX_BIT_PRECISION/8) + 2];
  174.     unit r[MAX_UNIT_PRECISION],quotient[MAX_UNIT_PRECISION];
  175.     word16 remainder;
  176.     char *bp = buf;
  177.     char minus = FALSE;
  178.     int places = 0;
  179.     int commaplaces;    /* put commas this many digits apart */
  180.     int i;
  181.  
  182.     /*    If string s is just an ESC char, don't print it.
  183.         It's just to inhibit the \n at the end of the number.
  184.     */
  185.     if ((s[0] != '\033') || (s[1] != '\0'))
  186.         putstr(s);
  187.  
  188.     if ( (radix < 2) || (radix > 16) )
  189.     {    putstr("****\n");    /* radix out of range -- show error */
  190.         return(-1);
  191.     }
  192.     commaplaces = (radix==10 ? 3 : (radix==16 ? 4 :
  193.             (radix==2 ? 8 : (radix==8 ? 8 : 1))));
  194.     mp_move(r,n);
  195.     if ((radix == 10) && mp_tstminus(r))
  196.     {    minus = TRUE;
  197.         mp_neg(r);    /* make r positive */
  198.     }
  199.  
  200.     *bp = '\0';
  201.     do    /* build backwards number string */
  202.     {    if (++places>1)
  203.             if ((places % commaplaces)==1)
  204.                 *++bp = ',';    /* 000,000,000,000 */
  205.         remainder = mp_shortdiv(quotient,r,radix);
  206.         *++bp = "0123456789ABCDEF" [remainder]; /* Isn't C wonderful? */
  207.         mp_move(r,quotient);
  208.     } while (testne(r,0));
  209.     if (minus)
  210.         *++bp = '-';
  211.     
  212.     if (commaplaces!=1)
  213.         while ((++places % commaplaces) != 1)
  214.             *++bp = ' '; /* pad to line up commas */
  215.  
  216.     i = string_length(s);
  217.     while (*bp)
  218.     {    putchar(*bp);
  219.         ++i;
  220.         if ((*bp == ',') || commaplaces==1)
  221.             if (i > (72-commaplaces))
  222.             {    putchar('\n'); 
  223.                 i=string_length(s);
  224.                 while (i--) putchar(' ');
  225.                 i = string_length(s);
  226.             }
  227.         bp--;
  228.     }
  229.     switch (radix)
  230.     {    /* show suffix character to designate radix */
  231.     case 10: /* decimal */
  232.         putchar('.');
  233.         break;
  234.     case 16: /* hex */
  235.         putchar('h');
  236.         break;
  237.     case 8: /* octal */
  238.         putchar('o');
  239.         break;
  240.     case 2: /* binary */
  241.         putchar('b');
  242.         break;
  243.     default: /* nonstandard radix */
  244.         /* printf("(%d)",radix); */ ;    
  245.     }
  246.  
  247.     if ((s[0] == '\033') && (s[1] == '\0'))
  248.         putchar(' ');    /* supress newline */
  249.     else putchar('\n');
  250.  
  251.     fill0((byteptr)buf,sizeof(buf));    /* burn the evidence on the stack...*/
  252.     /* Note that local stack arrays r and quotient are now 0 */
  253.     return(places);
  254. }    /* display_in_base */
  255.  
  256. #endif    /* DEBUG */
  257.  
  258. void mp_display(string s,unitptr r)
  259.     /* Display register r in hex, with prefix string s. */
  260. {    short precision;
  261.     int i,j;
  262.     putstr(s);
  263.     normalize(r,precision);    /* strip off leading zeros */
  264.     if (precision == 0)
  265.     {    putstr(" 0\n");
  266.         return;
  267.     }
  268.     make_msbptr(r,precision);
  269.     i=0;
  270.     while (precision--)
  271.     {    if (!(i++ % (16/BYTES_PER_UNIT)))
  272.         {    if (i>1)
  273.             {    putchar('\n'); 
  274.                 j=string_length(s); 
  275.                 while (j--) putchar(' ');
  276.             }
  277.         }
  278.         puthexunit(*r);
  279.         putchar(' ');
  280.         post_lowerunit(r);
  281.     }
  282.     putchar('\n');
  283. }    /* mp_display */
  284.  
  285.  
  286. word16 checksum(register byteptr buf, register word16 count)
  287.     /* Returns checksum of buffer. */
  288. {    word16 cs;
  289.     cs = 0;
  290.     while (count--) cs += *buf++;
  291.     return(cs);
  292. } /* checksum */
  293.  
  294.  
  295. void cbc_xor(register unitptr dst, register unitptr src, word16 bytecount)
  296.     /*    Performs the XOR necessary for RSA Cipher Block Chaining.
  297.         The dst buffer ought to have 1 less byte of significance than 
  298.         the src buffer.  Only the least significant part of the src 
  299.         buffer is used.  bytecount is the size of a plaintext block.
  300.     */
  301. {    short nunits;    /* units of precision */
  302.     nunits = bytes2units(bytecount)-1;
  303.     make_lsbptr(dst,global_precision);
  304.     while (nunits--)
  305.     {    *dst ^= *post_higherunit(src);
  306.         post_higherunit(dst);
  307.         bytecount -= units2bytes(1);
  308.     }
  309.     /* on the last unit, don't xor the excess top byte... */
  310.     *dst ^= (*src & (power_of_2(bytecount<<3)-1));
  311. }    /* cbc_xor */
  312.  
  313.  
  314. void hiloswap(byteptr r1,short numbytes)
  315.     /* Reverses the order of bytes in an array of bytes. */
  316. {    byteptr r2;
  317.     byte b;
  318.     r2 = &(r1[numbytes-1]);
  319.     while (r1 < r2)
  320.     {    b = *r1; *r1++ = *r2; *r2-- = b;
  321.     }
  322. }    /* hiloswap */
  323.  
  324.  
  325. #define byteglue(lo,hi) ((((word16) hi) << 8) + (word16) lo)
  326.  
  327. /****    The following functions must be changed if the external byteorder
  328.     changes for integers in PGP packet data.
  329. ****/
  330.  
  331.  
  332. word16 fetch_word16(byte *buf)
  333. /*    Fetches a 16-bit word from where byte pointer is pointing.
  334.     buf points to external-format byteorder array.
  335. */
  336. {    word16 w0,w1;
  337. /* Assume MSB external byte ordering */
  338.     w1 = *buf++;
  339.     w0 = *buf++;
  340.     return(w0 + (w1<<8));
  341. }    /* fetch_word16 */
  342.  
  343.  
  344. byte *put_word16(word16 w, byte *buf)
  345. /*    Puts a 16-bit word to where byte pointer is pointing, and 
  346.     returns updated byte pointer.
  347.     buf points to external-format byteorder array.
  348. */
  349. {
  350. /* Assume MSB external byte ordering */
  351.     buf[1] = w & 0xff;
  352.     w = w>>8;
  353.     buf[0] = w & 0xff;
  354.     return(buf+2);
  355. }    /* put_word16 */
  356.  
  357.  
  358. word32 fetch_word32(byte *buf)
  359. /*    Fetches a 32-bit word from where byte pointer is pointing.
  360.     buf points to external-format byteorder array.
  361. */
  362. {    word32 w0,w1,w2,w3;
  363. /* Assume MSB external byte ordering */
  364.     w3 = *buf++;
  365.     w2 = *buf++;
  366.     w1 = *buf++;
  367.     w0 = *buf++;
  368.     return(w0 + (w1<<8) + (w2<<16) + (w3<<24));
  369. }    /* fetch_word32 */
  370.  
  371.  
  372. byte *put_word32(word32 w, byte *buf)
  373. /*    Puts a 32-bit word to where byte pointer is pointing, and 
  374.     returns updated byte pointer.
  375.     buf points to external-format byteorder array.
  376. */
  377. {
  378. /* Assume MSB external byte ordering */
  379.     buf[3] = w & 0xff;
  380.     w = w>>8;
  381.     buf[2] = w & 0xff;
  382.     w = w>>8;
  383.     buf[1] = w & 0xff;
  384.     w = w>>8;
  385.     buf[0] = w & 0xff;
  386.     return(buf+4);
  387. }    /* put_word32 */
  388.  
  389.  
  390. /***    End of functions that must be changed if the external byteorder
  391.     changes for integer fields in PGP packets.
  392. ***/
  393.  
  394.  
  395.  
  396.  
  397. short mpi2reg(register unitptr r,register byteptr buf)
  398. /*    Converts a multiprecision integer from the externally-represented 
  399.     form of a byte array with a 16-bit bitcount in a leading length 
  400.     word to the internally-used representation as a unit array.
  401.     Converts to INTERNAL byte order.
  402.     The same buffer address may be used for both r and buf.
  403.     Returns number of units in result, or returns -1 on error.
  404. */
  405. {    byte buf2[MAX_BYTE_PRECISION];
  406.     word16 bitcount, bytecount, unitcount, zero_bytes, i;
  407.  
  408.     /* First, extract 16-bit bitcount prefix from first 2 bytes... */
  409.     bitcount = fetch_word16(buf);
  410.     buf += 2;
  411.  
  412.     /* Convert bitcount to bytecount and unitcount... */
  413.     bytecount = bits2bytes(bitcount);
  414.     unitcount = bytes2units(bytecount);
  415.     if (unitcount > global_precision)
  416.     {    /* precision overflow during conversion. */
  417.         return(-1);    /* precision overflow -- error return */
  418.     }
  419.     zero_bytes = units2bytes(global_precision) - bytecount;
  420. /* Assume MSB external byte ordering */
  421.     fill0(buf2,zero_bytes);  /* fill leading zero bytes */
  422.     i = zero_bytes;    /* assumes MSB first */
  423.     while (bytecount--) buf2[i++] = *buf++;
  424.  
  425.     mp_convert_order(buf2);    /* convert to INTERNAL byte order */
  426.     mp_move(r,(unitptr)buf2);
  427.     mp_burn((unitptr)buf2);    /* burn the evidence on the stack */
  428.     return(unitcount);    /* returns unitcount of reg */
  429. }    /* mpi2reg */
  430.  
  431.  
  432. short reg2mpi(register byteptr buf,register unitptr r)
  433. /*    Converts the multiprecision integer r from the internal form of 
  434.     a unit array to the normalized externally-represented form of a
  435.     byte array with a leading 16-bit bitcount word in buf[0] and buf[1].
  436.     This bitcount length prefix is exact count, not rounded up.
  437.     Converts to EXTERNAL byte order.
  438.     The same buffer address may be used for both r and buf.
  439.     Returns the number of bytes of the result, not counting length prefix.
  440. */
  441. {    byte buf1[MAX_BYTE_PRECISION];
  442.     byteptr buf2;
  443.     short bytecount,bc;
  444.     word16 bitcount;
  445.     bitcount = countbits(r);
  446. #ifdef DEBUG
  447.     if (bitcount > MAX_BIT_PRECISION)
  448.     {    fprintf(stderr, "reg2mpi: bitcount out of range (%d)\n", bitcount);
  449.         return 0;
  450.     }
  451. #endif
  452.     bytecount = bits2bytes(bitcount);
  453.     bc = bytecount;    /* save bytecount for return */
  454.     buf2 = buf1;
  455.     mp_move((unitptr)buf2,r);
  456.     mp_convert_order(buf2);    /* convert to EXTERNAL byteorder */
  457. /* Assume MSB external byte ordering */
  458.     buf2 += units2bytes(global_precision) - bytecount;
  459.     buf = put_word16(bitcount, buf); /* store bitcount in external byteorder */
  460.  
  461.     while (bytecount--) *buf++ = *buf2++;
  462.  
  463.     mp_burn((unitptr)buf1);    /* burn the evidence on the stack */
  464.     return(bc);        /* returns bytecount of mpi, not counting prefix */
  465. }    /* reg2mpi */
  466.  
  467.  
  468. #ifdef DEBUG
  469.  
  470. void dumpbuf(string s, byteptr buf, int bytecount)
  471.     /* Dump buffer in hex, with string label prefix. */
  472. {    putstr(s);
  473.     while (bytecount--)
  474.     {    puthexbyte(*buf++);
  475.         putchar(' ');
  476.         if ((bytecount & 0x0f)==0)
  477.             putchar('\n');
  478.     }
  479. } /* dumpbuf */
  480.  
  481. void dump_unit_array(string s, unitptr r)
  482. /*    Dump unit array r as a C array initializer, with string label prefix. 
  483.     Array is dumped in native unit order.
  484. */
  485. {    int unitcount;
  486.     unitcount = global_precision;
  487.     putstr(s);
  488.     putstr("\n{ ");
  489.     while (unitcount--)
  490.     {    putstr("0x");
  491.         puthexunit(*r++);
  492.         putchar(',');
  493.         if (unitcount && ((unitcount & 0x07)==0))
  494.             putstr("\n  ");
  495.     }
  496.     putstr(" 0};\n");
  497. } /* dump_unit_array */
  498.  
  499. #endif    /* ifdef DEBUG */
  500.  
  501.  
  502. /* ASN encoding for RSA/MD5 for PKCS compatibility */
  503. static unsigned char asn_array[] = {    /* PKCS 01 block type 01 data */
  504.     0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d,
  505.     0x02,0x05,0x05,0x00,0x04,0x10 };
  506. /* Count from end for zero */
  507. #define ASN_ZERO_END 3
  508.  
  509. /*
  510. **    short preblock(outreg, inbuf, bytecount, modulus, randompad)
  511. **
  512. **    A plaintext message must be converted into an integer less than
  513. **    the modulus n.  We do this by making it 1 byte shorter than the
  514. **    normalized modulus n.  Short blocks are left justified and padded.
  515. **
  516. **    The padding used depends on whether randompad is NULL.  First a
  517. **    0 byte is added beyond the data; then either 0xff's or values
  518. **    from randompad are added.  Last is a byte which tells whether
  519. **    we are preblocking a message digest or a conventional key; we
  520. **    assume that random padding is only used for conventional keys.
  521. **
  522. */
  523.  
  524. #ifdef PKCS_COMPAT
  525. /* Version for compatibility with PKCS */
  526.  
  527. short preblock(unitptr outreg, byteptr inbuf, short bytecount,
  528.     unitptr modulus, byteptr randompad)
  529. /*    Converts plaintext block into form suitable for RSA encryption.
  530.     inbuf contains the pointer to the data to be blocked.  To the
  531.     extent that it can be said to have a byte order, it should be
  532.     prepared MSB first.
  533.     Converts to an MPI in INTERNAL byte order.
  534.     Returns # of bytes remaining to process.  Note that the same buffer 
  535.     address may be used for both outreg and inbuf.
  536.     randompad is a pointer to a buffer of random pad bytes to use for 
  537.     padding material, or NULL iff we want to use constant padding.
  538. */
  539. {    byte out[MAX_BYTE_PRECISION];
  540.     short byte_precision,leading_zeros,remaining,blocksize,padding;
  541.     boolean mic_flag = (randompad==0);
  542.     int i,j;
  543.  
  544.     /* Our strategy is to fill the buffer in MSB-first order, then
  545.      * to call convert_order which will make it proper for an MPI.
  546.      */
  547.     byte_precision = units2bytes(global_precision);
  548.     leading_zeros = byte_precision - countbytes(modulus) + 1;
  549.     blocksize = byte_precision - leading_zeros;
  550.     /* note that blocksize includes data plus pad bytes, if any */
  551.  
  552.     padding = blocksize - 2 - (mic_flag?sizeof(asn_array):0) - bytecount;
  553.  
  554.     /* Remaining is # of bytes we can't do.  If it's negative it's the
  555.      * number more we could have done.
  556.      */
  557.     remaining = 1 - padding;    /* Padding must be >= 1 */
  558.  
  559.     if (remaining>0)        /* Just do a part of it */
  560.     {    bytecount -= remaining;
  561.         padding = 1;
  562.     }
  563.  
  564.     /* Start filling array, MSB first */
  565.     i = 0;
  566.  
  567.     while (leading_zeros--)
  568.         out[i++] = 0;
  569.  
  570.     /* Now we've gotten to the "mpi" part of the number */
  571.  
  572.     /* Now the type byte */
  573.     out[i++] = mic_flag ? MD_ENCRYPTED_BYTE : CK_ENCRYPTED_BYTE;
  574.  
  575.     /* Now padding: use either 0xff or values from randompad */
  576.     while (padding--)
  577.         out[i++] = mic_flag ? 0xff : *randompad++;
  578.  
  579.     /* A zero to separate things */
  580.     out [i++] = 0;
  581.  
  582.     /* Now ASN stuff if MIC (signature) */
  583.     if (mic_flag)
  584.         for (j=0; j<sizeof(asn_array); )
  585.             out[i++] = asn_array[j++];
  586.  
  587.     /* Now user data */
  588.     while (bytecount--)
  589.         out[i++] = *inbuf++;
  590.  
  591.     /* End of blocking logic */
  592.  
  593.     mp_move(outreg,(unitptr)out);
  594.     mp_burn((unitptr)out); /* burn the evidence on the stack */
  595.     mp_convert_order((byte *)outreg);    /* convert outreg to INTERNAL byte order */
  596.     return(remaining);    /* less than 0 if there was padding */
  597. }    /* preblock */
  598.  
  599. #else /* ! PKCS_COMPAT */
  600.  
  601. short preblock(unitptr outreg, byteptr inbuf, short bytecount,
  602.     unitptr modulus, byteptr randompad)
  603. /*    Converts plaintext block into form suitable for RSA encryption.
  604.     Converts to INTERNAL byte order.
  605.     Returns # of bytes remaining to process.  Note that the same buffer 
  606.     address may be used for both outreg and inbuf.
  607.     randompad is a pointer to a buffer of random pad bytes to use for 
  608.     padding material, or NULL iff we want to use constant padding.
  609. */
  610. {    byte out[MAX_BYTE_PRECISION];
  611.     short byte_precision,leading_zeros,remaining,blocksize;
  612.     int i;
  613.  
  614.     byte_precision = units2bytes(global_precision);
  615.     leading_zeros = byte_precision - countbytes(modulus) + 1;
  616.     blocksize = byte_precision - leading_zeros;
  617.     /* note that blocksize includes data plus pad bytes, if any */
  618.  
  619.     remaining = bytecount - blocksize;
  620.     if (remaining>=0)
  621.         bytecount = blocksize;
  622.     i = 0;
  623.  
  624. /* Assume MSB external byte ordering */
  625.     while (leading_zeros--)    /* assumes MSB first */
  626.         out[i++] = 0;
  627.  
  628.     while (bytecount--)        /* copy user data */
  629.         out[i++] = *inbuf++;
  630.  
  631.     out    [i++] = 0;            /* Always start with a 0 for padding */
  632.  
  633. /* Assume MSB external byte ordering */
  634.     /* Pad with either 0xff or values from randompad */
  635.     while (i < byte_precision - 1)
  636.         out[i++] = randompad ? *randompad++ : 0xff;
  637.  
  638.     /* End with type byte, which we deduce from randompad */
  639.     out[i++] = randompad ? CK_ENCRYPTED_BYTE : MD_ENCRYPTED_BYTE;
  640.  
  641.     /* End of padding logic */
  642.  
  643.     mp_move(outreg,(unitptr)out);
  644.     mp_burn((unitptr)out); /* burn the evidence on the stack */
  645.     mp_convert_order((byte *)outreg);    /* convert outreg to INTERNAL byte order */
  646.     return(remaining);    /* less than 0 if there was padding */
  647. }    /* preblock */
  648. #endif /* PKCS_COMPAT */
  649.  
  650.  
  651. short postunblock(byteptr outbuf, unitptr inreg, unitptr modulus)
  652. /*    Converts a just-decrypted RSA block back into unblocked plaintext form.
  653.     Converts to EXTERNAL byte order.
  654.     See the notes on preblocking in the preblock routine above.
  655.     Note that outbuf must be at least as large as inreg.
  656.     The same buffer address may be used for both outbuf and inreg.
  657.     Returns positive bytecount of plaintext, or negative error status.
  658.     -1 is bad packet; -2 is unrecognized digest algorithm.
  659. */
  660. {    short i,j,byte_precision,leading_zeros,bytecount;
  661.     short    blocksize;
  662.     boolean constpad;
  663.  
  664.     byte_precision = units2bytes(global_precision);
  665.     leading_zeros = byte_precision - countbytes(modulus) + 1;
  666.     blocksize = byte_precision - leading_zeros;
  667.     /* note that blocksize includes data plus pad bytes, if any */
  668.  
  669.     mp_move((unitptr)outbuf,inreg);
  670.     mp_convert_order(outbuf);    /* convert to EXTERNAL byte order */
  671.  
  672.     /* Determine if it is the PKCS format or the older format.
  673.      * PKCS keys must be >= 48 bytes (384 bits).  DEK keys have a 2
  674.      * as the MSB.  Pre-PKCS keys and PKCS MICs have 1 there.  PKCS
  675.      * MICs have a 0 at a certain point in the ASN string, a point
  676.      * where non-PKCS strings have non-zero padding.  That's how we
  677.      * tell.
  678.      */
  679.     if (byte_precision < 48  ||
  680.         (outbuf[leading_zeros] == 1  &&
  681.          (outbuf[byte_precision-1]==1 || outbuf[byte_precision-1]==2) &&
  682.          outbuf[byte_precision-16-ASN_ZERO_END] != 0))
  683.     { /* Pre-2.3 format */
  684.     /* Check high byte, make sure it's legal, figure out padding type */
  685. /* Assume MSB external byte ordering */
  686.     i = byte_precision - 1;
  687.     if (outbuf[i] == MD_ENCRYPTED_BYTE)
  688.         constpad = 1;
  689.     else if (outbuf[i] == CK_ENCRYPTED_BYTE)
  690.         constpad = 0;
  691.     else
  692.             return(-2);
  693.  
  694.     /* Scan down for the 0 byte that ends padding */
  695.     while (--i > 0  &&  outbuf[i])
  696.         if (constpad && outbuf[i] != 0xff)
  697.             return(-1);
  698.  
  699. /* Assume MSB external byte ordering */
  700.     bytecount = i - leading_zeros;
  701.     if (leading_zeros)
  702.         for (i = 0; i < bytecount; ++i)
  703.             outbuf[i] = outbuf[i+leading_zeros];
  704.  
  705.     /* Zero out high part of buffer to make it look nice */
  706.     while (i < byte_precision)
  707.         outbuf[i++] = 0;
  708.     }
  709.     else
  710.     { /* PKCS compatible format */
  711.         /* Determine which type it is */
  712.         i = leading_zeros;
  713.         if (outbuf[i] == MD_ENCRYPTED_BYTE)
  714.             constpad = 1;
  715.         else if (outbuf[i] == CK_ENCRYPTED_BYTE)
  716.             constpad = 0;
  717.         else
  718.             return(-1);
  719.  
  720.         /* Scan for the 0 byte that ends padding */
  721.         while (++i<byte_precision  &&  outbuf[i])
  722.             if (constpad && outbuf[i] != 0xff)
  723.                 return(-1);
  724.  
  725.         i++;
  726.  
  727.         /* Verify ASN material for MICs */
  728.         if (constpad)
  729.         {    if (memcmp(outbuf+i, asn_array, sizeof(asn_array)) != 0)
  730.                 return(-2);
  731.             i += sizeof(asn_array);
  732.         }
  733.  
  734.         /* Copy remaining material down to the front of the buffer */
  735.         bytecount = byte_precision - i;
  736.         for (j=0; j<bytecount; )
  737.             outbuf[j++] = outbuf[i++];
  738.  
  739.         /* Zero out high part of buffer to make it look nice */
  740.         while (j < byte_precision)
  741.             outbuf[j++] = 0;
  742.     }
  743.  
  744.     return(bytecount);    /* normal return */
  745. }    /* postunblock */
  746.  
  747. /************ end of multiprecision integer I/O library *****************/
  748.  
  749.